#pragma once
#include <string>
using std::string;

#include "crypto++/aes.h"  
#include "crypto++/md5.h"  
#include "crypto++/hex.h"  
#include "crypto++/files.h"  
#include "crypto++/default.h"  
#include "crypto++/filters.h"  
#include "crypto++/osrng.h"  

using namespace CryptoPP;

#ifndef libAES_H
#define libAES_H

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1  


class libAES
{
public:

	enum AESKeyLength
	{
		AES_KEY_LENGTH_16 = 16, AES_KEY_LENGTH_24 = 24, AES_KEY_LENGTH_32 = 32
	};

	int encrypt4aes(const std::string &inData, const std::string &strKey, std::string &outData, std::string &errMsg);


	int decrypt4aes(const std::string &inData, const std::string &strKey, std::string &outData, std::string &errMsg);


	string md5(const std::string& inData)
	{
		std::string digest;
		Weak1::MD5 md5;
		StringSource(inData, true,
			new HashFilter(md5, new HexEncoder(new StringSink(digest))));

		return digest;
	}
};
#endif //libAES_H

int libAES::encrypt4aes(const std::string & inData, const std::string & strKey, std::string & outData, std::string & errMsg)
{
	outData = "";
	errMsg = "";

	if (inData.empty() || strKey.empty())
	{
		errMsg = "indata or key is empty!!";
		return -1;
	}

	unsigned int iKeyLen = strKey.length();

	if (iKeyLen != AES_KEY_LENGTH_16 && iKeyLen != AES_KEY_LENGTH_24
		&& iKeyLen != AES_KEY_LENGTH_32)
	{
		errMsg = "aes key invalid!!";
		return -2;
	}

	byte iv[AES::BLOCKSIZE];
	int iResult = 0;

	try
	{
		CBC_Mode<AES>::Encryption e;
		e.SetKeyWithIV((byte*)strKey.c_str(), iKeyLen, iv);
		StringSource ss(inData, true,
			new StreamTransformationFilter(e, new StringSink(outData)));
	}
	catch (const CryptoPP::Exception& e)
	{
		errMsg = "Encryptor throw exception!!";
		iResult = -3;
	}

	return iResult;
}

int libAES::decrypt4aes(const std::string & inData, const std::string & strKey, std::string & outData, std::string & errMsg)
{
	outData = "";
	errMsg = "";

	if (inData.empty() || strKey.empty())
	{
		errMsg = "indata or key is empty!!";
		return -1;
	}

	unsigned int iKeyLen = strKey.length();

	if (iKeyLen != AES_KEY_LENGTH_16 && iKeyLen != AES_KEY_LENGTH_24
		&& iKeyLen != AES_KEY_LENGTH_32)
	{
		errMsg = "aes key invalid!!";
		return -2;
	}

	byte iv[AES::BLOCKSIZE];
	int iResult = 0;

	try
	{
		CBC_Mode<AES>::Decryption d;
		d.SetKeyWithIV((byte*)strKey.c_str(), iKeyLen, iv);
		StringSource ss(inData, true,
			new StreamTransformationFilter(d, new StringSink(outData)));
	}
	catch (const CryptoPP::Exception& e)
	{
		errMsg = "Encryptor throw exception";
		iResult = -3;
	}

	return iResult;
}
